package com.cls.business.service.impl;

import com.cls.business.entity.*;
import com.cls.business.mapper.*;
import com.cls.business.service.ILogDeclareTopicService;
import com.cls.common.entity.QueryRequest;
import com.cls.business.service.ITopicPlanService;
import com.cls.common.enums.DictEnum;
import com.cls.common.utils.EmailSenderUtil;
import com.cls.common.utils.StringUtils;
import com.cls.system.entity.Expert;
import com.cls.system.entity.User;
import com.cls.system.mapper.ExpertMapper;
import com.cls.system.mapper.UserMapper;
import com.github.pagehelper.PageHelper;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;
import lombok.RequiredArgsConstructor;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.*;

/**
 * 课题计划表 Service实现
 *
 * @author wmm
 * @date 2020-11-11 10:45:55
 */
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class TopicPlanServiceImpl extends ServiceImpl<TopicPlanMapper, TopicPlan> implements ITopicPlanService {

    @Autowired
    ILogDeclareTopicService logDeclareTopicService;

    @Autowired
    ExpertAllocationService expertAllocationService;

    @Autowired
    DeclarePlanMapper declarePlanMapper;

    @Autowired
    DeclareTopicMapper declareTopicMapper;

    @Autowired
    TopicMapper topicMapper;

    @Autowired
    EntrustTopicMapper entrustTopicMapper;

    @Autowired
    ReviewMapper reviewMapper;

    @Autowired
    ReviewDetailMapper reviewDetailMapper;

    @Autowired
    ExpertGroupMapper expertGroupMapper;

    @Autowired
    TopicSubjectMapper topicSubjectMapper;

    @Autowired
    TopicSubjectDetailMapper topicSubjectDetailMapper;

    @Autowired
    ExpertMapper expertMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    EmailSenderUtil emailSenderUtil;

    @Override
    public PageInfo<TopicPlan> findTopicPlans(QueryRequest request, TopicPlan topicPlan) {
        LambdaQueryWrapper<TopicPlan> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(topicPlan.getYear())) {
            queryWrapper.eq(TopicPlan::getYear, topicPlan.getYear());
        }

        if (StringUtils.isNotEmpty(topicPlan.getTopicClassifyCode())) {
            queryWrapper.eq(TopicPlan::getTopicClassifyCode, topicPlan.getTopicClassifyCode());
        }

        if (StringUtils.isNotEmpty(topicPlan.getPeriod())) {
            queryWrapper.eq(TopicPlan::getPeriod, topicPlan.getPeriod());
        }

        queryWrapper.orderByDesc(TopicPlan::getYear);
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<TopicPlan> list = this.list(queryWrapper);
        PageInfo pageInfo = new PageInfo(list);
        return pageInfo;
    }

    @Override
    public List<TopicPlan> findTopicPlans(TopicPlan topicPlan) {
        LambdaQueryWrapper<TopicPlan> queryWrapper = new LambdaQueryWrapper<>();
        // TODO 设置查询条件
        if (topicPlan.getYear() != null) {
            queryWrapper.eq(TopicPlan::getYear, topicPlan.getYear());
        }
        if (StringUtils.isNotEmpty(topicPlan.getTopicClassifyCode())) {
            queryWrapper.eq(TopicPlan::getTopicClassifyCode, topicPlan.getTopicClassifyCode());
        }
        if (StringUtils.isNotEmpty(topicPlan.getPeriod())) {
            queryWrapper.eq(TopicPlan::getPeriod, topicPlan.getPeriod());
        }
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public TopicPlan findById(Long id) {
        return this.baseMapper.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createTopicPlan(TopicPlan topicPlan) {
        this.save(topicPlan);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTopicPlan(TopicPlan topicPlan) {
        this.saveOrUpdate(topicPlan);
    }


    /**
     * 删除
     *
     * @param ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTopicPlans(String[] ids) {
        List<String> list = Arrays.asList(ids);
        this.removeByIds(list);
    }

    /**
     * 根据SelectNoticeId查询
     *
     * @param selectNoticeId
     * @return
     */
    @Override
    public TopicPlan selectBySelectNoticeId(Long selectNoticeId) {
        return this.baseMapper.selectBySelectNoticeId(selectNoticeId);
    }


    /**
     * 根据ApplyNoticeId查询
     *
     * @param applyNoticeId
     * @return
     */
    @Override
    public TopicPlan selectByApplyNoticeId(Long applyNoticeId) {
        return this.baseMapper.selectByApplyNoticeId(applyNoticeId);
    }


    @Override
    public TopicPlan selectByPeriod(String period) {
        if (StringUtils.isEmpty(period)) {
            return null;
        }
        LambdaQueryWrapper<TopicPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TopicPlan::getPeriod,period);
        return this.baseMapper.selectOne(queryWrapper);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTopicPlanStatusCode(TopicPlan topicPlan) {
        LogDeclareTopic logDeclareTopic = new LogDeclareTopic();
        logDeclareTopic.setStatusTypeCode(topicPlan.getStatusCode());
        logDeclareTopic.setOperatorTime(new Date());
        logDeclareTopic.setPlanId(topicPlan.getPlanId());
        User curUser = (User) SecurityUtils.getSubject().getPrincipal();
        if (curUser != null) {
            logDeclareTopic.setOperatorBy(curUser.getUserId());
        }
        logDeclareTopicService.createLogDeclareTopic(logDeclareTopic);
        saveOrUpdate(topicPlan);
    }

    /**
     * 魏起成根据年份更新计划状态
     *
     * @param year
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatusCodeByYear(Integer year, String statusCode) {
        this.baseMapper.updateStatusCodeByYear(year, statusCode);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean endClassifyTopic(TopicPlan plan) {
        List<Topic> topics = topicMapper.selectListByPlanId(plan.getPlanId());
        List<ITopic> iTopics = new ArrayList();
        for (ITopic one : topics) {
            one.setStatusTypeCode(DictEnum.PLAN_SUBJECT.getCode());
            iTopics.add(one);
        }
        boolean status = expertAllocationService.run(plan.getPlanId(), iTopics);
        if (!status) {
            return false;
        } else {
            updateTopicPlanStatusCode(plan);
            for (Topic one : topics) {
                topicMapper.updateById(one);
            }
            return true;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean endClassifyEntrustTopic(TopicPlan plan) {
        List<EntrustTopic> topics = entrustTopicMapper.selectByPlanId(plan.getPlanId());
        List<ITopic> iTopics = new ArrayList();
        for (ITopic one : topics) {
            one.setStatusTypeCode(DictEnum.PLAN_SUBJECT.getCode());
            iTopics.add(one);
        }
        boolean succeed = expertAllocationService.run(plan.getPlanId(), iTopics);
        if (succeed) {
            updateTopicPlanStatusCode(plan);
            for (EntrustTopic one : topics) {
                entrustTopicMapper.updateById(one);
            }
        }
        return succeed;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean endAssignTopicPlan(TopicPlan plan) {
        updateTopicPlanStatusCode(plan);
        List<DeclarePlan> declarePlans = declarePlanMapper.selectDeclarePlansByPlanId(plan.getPlanId());
        Map<Long, EntrustTopic> topics = new HashMap();
        for (DeclarePlan one : declarePlans) {
            DeclareTopic declareTopic = new DeclareTopic();
            declareTopic.setDeclareId(one.getDeclareId());
            declareTopic.setStatusTypeCode(DictEnum.CONCLUDE_ASSIGN.getCode());
            declareTopicMapper.updateById(declareTopic);
            Long topicId = one.getTopicId();
            if (topicId != null) {
                EntrustTopic entrustTopic = topics.get(topicId);
                if (entrustTopic == null) {
                    Topic topic = topicMapper.selectById(topicId);
                    entrustTopic = new EntrustTopic(topic);
                    entrustTopic.setPlanId(plan.getPlanId());
                    entrustTopic.setStage(plan.getPeriod());
                    entrustTopic.setStatusTypeCode(DictEnum.PLAN_ASSIGN.getCode());
                    entrustTopic.setEntrustTopicId(topicId);
                    entrustTopicMapper.insert(entrustTopic);
                    topics.put(topicId, entrustTopic);
                }
                one.setPlanTopicId(entrustTopic.getTopicId());
                declarePlanMapper.updateById(one);
            }
        }

        return true;
    }

    /**
     * 根据年份查询年度课题
     *
     * @param year
     * @return
     */
    @Override
    public TopicPlan selectAnnualByYear(String year) {
        return this.baseMapper.selectByYearAndTopicClassify(year, DictEnum.ANNUAL.getCode());
    }

    @Transactional
    @Override
    public boolean assignEntrust(Long planId, Long declarePlanId) {
        DeclarePlan declarePlan = new DeclarePlan();
        declarePlan.setDeclarePlanId(declarePlanId);
        declarePlan.setPlanId(planId);
        declarePlanMapper.updateById(declarePlan);
        return true;
    }

    @Transactional
    @Override
    public boolean unAssignEntrusts(Long declarePlanId) {
        declarePlanMapper.clearPlanIdByDeclarePlanId(declarePlanId);
        return true;
    }

    /**
     * 魏起成 根据classifyCode  statusCode 与 未定级数量=0   查询计划
     *
     * @return
     */
    @Override
    public List<TopicPlan> findTopicByClassifyCodeAndNoLevel() {
        return topicMapper.selectNoLevelByClassifyCodeAndStatusCode(DictEnum.ENTRUST.getCode(), DictEnum.PLAN_REVIEW.getCode());
    }

    @Override
    public TopicPlan selectByPreItemNoticeId(Long preItemNoticeId) {
        return this.baseMapper.selectByPreItemNoticeId(preItemNoticeId);
    }

    @Override
    public TopicPlan selectByConcludeNoticeId(Long concludeNoticeId) {
        return this.baseMapper.selectByConcludeNoticeId(concludeNoticeId);
    }

    @Transactional
    @Override
    public boolean resumeInitialization(TopicPlan plan) {
        boolean isAnnual = true;
        if (DictEnum.ENTRUST.getCode().equals(plan.getTopicClassifyCode())) {
            isAnnual = false;
        }

        // (课题)：课题状态变为资格审查通过
        List<DeclareTopic> declareTopics = declareTopicMapper.selectByPlanId(plan.getPlanId());
        List<String> status = new ArrayList();
        status.add(DictEnum.NO_APPLY.getCode());
        status.add(DictEnum.PRE_APPLY.getCode());
        status.add(DictEnum.CHECK_FAILED.getCode());
        for (DeclareTopic one : declareTopics) {
            if (isAnnual && !status.contains(one.getStatusTypeCode())) {
                one.setStatusTypeCode(DictEnum.CHECK_PASSED.getCode());
            } else if (!isAnnual) {
                one.setStatusTypeCode(DictEnum.CONCLUDE_APPLY.getCode());
            }
            declareTopicMapper.updateById(one);
        }

        // (评审记录)：删除评审记录
        reviewDetailMapper.deleteByPlanId(plan.getPlanId());
        reviewMapper.deleteByPlanId(plan.getPlanId());
        expertGroupMapper.deleteByPlanId(plan.getPlanId());

        // (学科分类)：删除学科分类
        topicSubjectDetailMapper.deleteByPlanId(plan.getPlanId());
        topicSubjectMapper.deleteByPlanId(plan.getPlanId());


        // (选题)：选题状态变为create
        if (isAnnual) {
            List<Topic> topics = topicMapper.selectListByPlanId(plan.getPlanId());
            for (Topic one : topics) {
                one.setStatusTypeCode(DictEnum.PLAN_CREATE.getCode());
                topicMapper.updateById(one);
            }
        } else {
            List<EntrustTopic> topics = entrustTopicMapper.selectByPlanId(plan.getPlanId());
            for (EntrustTopic one : topics) {
//                one.setStatusTypeCode(DictEnum.PLAN_CREATE.getCode());
//                entrustTopicMapper.updateById(one);
                entrustTopicMapper.deleteById(one.getTopicId());
            }
        }

        // (计划)：计划状态变为create
        plan.setStatusCode(DictEnum.PLAN_CREATE.getCode());
        baseMapper.updateById(plan);
        return true;
    }

    /**
     * 根据立项公告id查询
     *
     * @param itemNoticeId
     * @return
     */
    @Override
    public TopicPlan selectItemNoticeId(Long itemNoticeId) {
        return this.baseMapper.selectItemNoticeId(itemNoticeId);
    }

    @Override
    public int sendReviewEmail(TopicPlan plan) {
        List<Expert> experts = expertMapper.selectReviewExpertByPlanId(plan.getPlanId());
        List<String> messages = new ArrayList<>();
        messages.add(plan.getYear());
        String password = "123456";
        for (Expert expert : experts) {
            User user = userMapper.selectById(expert.getUserId());
            if (user == null) {
                continue;
            }
            messages.clear();
            messages.add(plan.getYear());
            String mobile = expert.getMobile();
            if (mobile != null && mobile.length() > 10) {
                password = mobile.substring(3, 9);
            }

            if (DictEnum.ENTRUST.getCode().equals(plan.getTopicClassifyCode())) {
                messages.add(plan.getPeriod());
                messages.add(user.getUsername());
                messages.add(password);
                emailSenderUtil.sendEntrustPromptEmail(expert.getEmail(), messages);
            } else {
                messages.add(user.getUsername());
                messages.add(password);
                emailSenderUtil.sendAnnualPromptEmail(expert.getEmail(), messages);
            }

        }
        return 0;
    }

    @Override
    public TopicPlan selectNoticeByConcludeFinishNoticeId(Long concludeFinishNoticeId) {
        return baseMapper.selectNoticeByConcludeFinishNoticeId(concludeFinishNoticeId);
    }
}
